import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, NgZone, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { NzModalRef, NzModalService, NzModalState } from 'ng-zorro-antd/modal';
import { Host, HostConfigService, Setting, SettingService } from '../../service/config.service';
import { ElectronService } from '../../service/electron.service';
import { NotifyService } from '../../service/notify.service';
import { ThemeService } from '../../service/theme.service';
import { LogService } from '../../service/log.service';
import { TermComponent } from '../../components/tab/term/term.component';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.css']
})
export class MainComponent implements OnInit, OnDestroy, AfterViewInit {
  isCollapsed = true;
  tablist = [];
  selectedIndex = 0;
  setting: Setting;

  constructor(private modal: NzModalService,
    public electron: ElectronService,
    private cd: ChangeDetectorRef,
    private nzContexMenuService: NzContextMenuService,
    private notify: NotifyService,
    private hostCfg: HostConfigService,
    private settingService: SettingService,
    private themeService: ThemeService,
    private logger: LogService,
    private zone: NgZone) {
    this.setting = this.settingService.getConfig();
  }

  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
    this.nzContexMenuService.create($event, menu);
  }

  ngOnInit() {
    document.addEventListener('contextmenu', function (e) {
      e.preventDefault();
    })
    this.notify.onOpenTab(tab => {
      if (tab.type == 'local') this.newLocalShell();
      else this.addTab(tab);
    })
  }
  ngOnDestroy() {
    this.tablist = [];
  }
  ngAfterViewInit() {
    this.logger.info("main app init complete")
    this.cd.detectChanges();
    if (this.electron.isElectron) {
      this.electron.ipcRenderer.on('win-close-confirm', () => this.zone.run(() => {
        this.logger.info("recv close")
        this.closeAppConfirm();
      }))
    }
  }
  getOriginTitle(host: Host) {
    if (host == null) return 'Local Terminal';
    return host.title;
    /*if (host.child){
      return this.getOriginTitle(host.child);
    }else{
      return host.title;
    }*/
  }
  getInitalTitle(title, index) {
    if (index == 0) return title;
    else return title + '(' + index + ')';
  }
  getTitleIndex(type, origin_title): number {
    let index = 0;
    let used_index = {};
    for (let i = 0; i < this.tablist.length; i++) {
      let tab = this.tablist[i];
      if (tab.origin_title == origin_title && tab.type == type) {
        if (tab.title == this.getInitalTitle(tab.origin_title, tab.title_index)) {
          used_index[tab.title_index] = true;
          index += 1;
        }
      }
    }
    for (let i = 0; i < index; i++) {
      if (!used_index[i])
        return i;
    }
    return index;
  }
  closeTab(ev, flag: "current" | "all" | "others" = "current"): void {
    let _close = () => {
      //ev.close();
      let tabs = this.tablist;
      let index = ev ? ev.index - 1 : 0;
      if (flag == "current") {
        tabs.splice(index, 1);
      } else if (flag == "all") {
        tabs.splice(0, tabs.length);
      } else if (flag == "others") {
        tabs.splice(0, tabs.length, tabs[index]);
      }
    }
    if (this.setting.terminal.closeConfirm) {
      this.confirmModal = this.modal.confirm({
        nzTitle: 'Do you want to close?',
        nzContent: '',
        nzOkText: 'Yes',
        nzOkType: 'primary',
        nzOkDanger: true,
        nzOnOk: _close,
        nzCancelText: 'No'
      })
    } else {
      _close();
    }

  }
  addTab(tab: { type: string, host: any }, pos = -1) {
    let origin_title = this.getOriginTitle(tab.host);
    let title_index = this.getTitleIndex(tab.type, origin_title);
    let newTab = {
      type: tab.type,
      showChange: false,
      showError: false,
      host: tab.host,
      icon: this.hostCfg.getIconByType(tab.type),
      origin_title: origin_title,
      title_index: title_index,
      title: this.getInitalTitle(origin_title, title_index)
    }
    this.hostCfg.saveHistory(tab.type, tab.host);
    if (pos == -1) {
      this.tablist.push(newTab);
      pos = this.tablist.length;
    } else {
      this.tablist.splice(pos + 1, 0, newTab);
      pos = pos + 2;
    }
    //setTimeout(() => {
    this.selectedIndex = pos;
    this.tablist[this.selectedIndex - 1].showChange = false;
    //  this.notify.emitMainTabIndexChange(this.selectedIndex - 1);
    //});
  }

  dupTab(tab, index, type) {
    this.addTab({ type: type, host: tab.host }, index);
  }
  @ViewChildren(TermComponent) termTabList: QueryList<TermComponent>;
  splitTab(index) {
    this.termTabList.forEach(item => {
      if (item.tabIndex == index) {
        item.split();
      }
    })
  }
  reconnect(index) {
    this.termTabList.forEach(item => {
      if (item.tabIndex == index) {
        item.reconnect();
      }
    })
  }
  toggleDirection(index) {
    this.termTabList.forEach(item => {
      if (item.tabIndex == index) {
        item.toggleDirection();
      }
    })
  }
  newLocalShell() {
    this.addTab({ type: 'local', host: null });
  }
  onTabStateChange(index, msg) {
    if (msg == 'CONNECTING') {
      this.tablist[index].isLoading = true;
      this.tablist[index].showError = false;
      this.tablist[index].showChange = false;
    } else {
      this.tablist[index].isLoading = false;
    }
    if (msg == 'ERROR') {
      this.tablist[index].showError = true;
      this.tablist[index].showChange = false;
    }
    else if (this.selectedIndex != index + 1) {
      this.tablist[index].showError = false;
      this.tablist[index].showChange = true;
    }
  }
  onSelectTabChange(index) {
    if (index > 0) {
      this.tablist[index - 1].showChange = false;
      //this.notify.emitMainTabIndexChange(index - 1);
    }
  }
  onTabDragDrop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.tablist, event.previousIndex, event.currentIndex);
  }
  confirmModal?: NzModalRef;
  closeAppConfirm() {
    if (!this.confirmModal || this.confirmModal.state != NzModalState.OPEN) {
      this.confirmModal = this.modal.confirm({
        nzTitle: 'Do you want to quit?',
        nzContent: '',
        nzOkText: 'Yes',
        nzOkType: 'primary',
        nzOkDanger: true,
        nzOnOk: () => this.electron.windowOper('window-close'),
        nzCancelText: 'No'
      })
    }
  }
  windowOper(oper: string) {
    //console.log(oper);
    //this.electron.ipcRenderer.send(oper);
    if (oper == 'window-close') {
      this.closeAppConfirm();
    } else {
      this.electron.windowOper(oper);
    }
  }
  @HostListener('window:keydown', ['$event'])
  handleKeyDown(event: KeyboardEvent) {
    //console.log(event.keyCode, event.key)
    if (event.ctrlKey && event.keyCode == 9) {
      this.selectedIndex += 1;
      this.selectedIndex %= this.tablist.length + 1;
    } else if (event.ctrlKey && event.keyCode >= 49 && event.keyCode <= 57 && event.keyCode - 49 <= this.tablist.length) {
      this.selectedIndex = event.keyCode - 49;
    }
  }
  @ViewChildren("popRename", { read: ElementRef }) pop: QueryList<ElementRef>;
  newTitle: string;
  renameTitle(index) {
    this.newTitle = this.tablist[index].title;
    this.pop.toArray()[index].nativeElement.click();
  }
  confirmRename(index) {
    this.tablist[index].title = this.newTitle;
  }


  /* tree view */
  /*
  isTreeViewOpened = false;
  selectedHost: Host;
  private transformer = (host: Host, level: number) => {
    return {
      expandable: !!host.children && host.children.length > 0,
      name: host.title,
      level: level,
      host: host
    };
  };
  treeFlattener = new NzTreeFlattener(
    this.transformer,
    node => node.level,
    node => node.expandable,
    node => node.children
  );
  treeControl  = new FlatTreeControl<any>(
    node => node.level,
    node => node.expandable
  );
  dataSource = new NzTreeFlatDataSource(this.treeControl, this.treeFlattener);
  selectListSelection= new SelectionModel<any>(true);
  showTreeView(show){
    if (show){
    this.dataSource.setData(this.hostCfg.getHostConfig().children);
    this.treeControl.expandAll();
    this.isTreeViewOpened = true;
    }
    else{
      this.isTreeViewOpened = false;
    }
  }
  clickTreeNode(node){
    let nodes = this.dataSource._flattenedData.value;
    this.selectedHost = node.host;
    for (let i=0; i<nodes.length; i++){
      if (nodes[i] == node){
        if (!this.selectListSelection.isSelected(nodes[i]))this.selectListSelection.toggle(nodes[i]);
      }
      else{
        if (this.selectListSelection.isSelected(nodes[i]))this.selectListSelection.toggle(nodes[i]);
      }
    }
  }
  confirmTreeNode(type){
    this.isTreeViewOpened = false;
    this.notify.emitOpenTab({type: type, host: this.hostCfg.getConnectHost(this.selectedHost)});
    //this.addTab({type:type, host:this.selectedHost});
  }
  isHostWithChild = (_: number, node: any) => this.hostCfg.isHost(node.host) && node.host.children && node.host.children.length > 0;
  isForward = (_: number, node: any) => this.hostCfg.isForward(node.host);
  isGroup= (_: number, node: any) => this.hostCfg.isGroup(node.host);
  isHostSelected = () => {return this.hostCfg.isNotForward(this.selectedHost);}
  isForwardSelected = () => {return this.hostCfg.isForward(this.selectedHost);}*/
  isTreeViewOpened = false;
  showTreeView(show) {
    this.isTreeViewOpened = show;
  }
  confirmTreeNode(type, host = null) {
    this.isTreeViewOpened = false;
    this.notify.emitOpenTab({ type: type, host: host });
  }
  onHostTreeDblClick(host) {
    if (this.hostCfg.isGroup(host)) return;
    let type = this.hostCfg.isForward(host) ? 'forward' : 'ssh';
    this.confirmTreeNode(type, host);
  }
  toggleDarkMode() {
    this.setting.global.darkMode = !this.setting.global.darkMode;
    this.themeService.changeTheme(this.setting.global.darkMode).then();
  }
  showAbout() {
    this.modal.confirm({
      nzTitle: 'SSH Terminal with Angular',
      nzContent: '',
      nzOkText: 'OK',
      nzOkType: 'primary',
      nzCancelText: null
    })
  }
}
